#include "Database.h"
#include "../../protocols/oscar/OscarProtData.h"
#include <iostream>
#include <string>
#include <stdio.h>
#include "../Impp.h"

using namespace std;

namespace Impp{

Database::Database(const wxString & profilFile) :
	db(),notInListGroup(NULL)
{
	open(profilFile);
	createGroupTable();
	createBuddyTable();
	createModuleTable();
	createValueTables();
	createHistoryTable();
	createStatusMessageTable();
	createAccountsTable();
	checkDatabaseTables();
}

Database::~Database()
{
		close();
}

void Database::open(const wxString & profilFile){
	try{
	   db.Open(profilFile);
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::open: Exception: %s"), e.GetMessage().c_str());
		wxLogError(wxT("Database::open: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::createBuddyTable(){
	try{
		db.ExecuteUpdate(
			wxT("CREATE TABLE IF NOT EXISTS buddy (\
				 id INTEGER UNIQUE PRIMARY KEY,\
				 account_id INTEGER,\
				 screen_name TEXT,\
				 custom_name TEXT,\
				 group_id INTEGER,\
				 flags INTEGER\
			     )")
		 );
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createBuddyTable: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::createGroupTable(){
	try{
		db.ExecuteUpdate(
			wxT("CREATE TABLE IF NOT EXISTS gp (\
				 id INTEGER UNIQUE PRIMARY KEY,\
				 name TEXT,\
				 flags INTEGER\
			     )")
		 );
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createGroupTable: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::createModuleTable(){
	try{
		db.ExecuteUpdate(
			wxT("CREATE TABLE IF NOT EXISTS module (\
				 id INTEGER UNIQUE PRIMARY KEY,\
				 name TEXT,\
				 type INTEGER,\
				 classname TEXT,\
				 flags INTEGER\
				)")
	    );
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createModuleTable: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::createAccountsTable(){
	try{
		db.ExecuteUpdate(
			wxT("CREATE TABLE IF NOT EXISTS accounts (\
				 id INTEGER UNIQUE PRIMARY KEY,\
				 flags INTEGER,\
				 self INTEGER,\
				 classname TEXT,\
			     screenname TEXT,\
				 password TEXT\
				)")
	    );
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createAccountsTable: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::createValueTables(){
	try{
		db.ExecuteUpdate(
			wxT("CREATE TABLE IF NOT EXISTS module_value (\
				 id INTEGER UNIQUE PRIMARY KEY,\
				 name TEXT,\
			     value NONE,\
				 moduleId INTEGER\
				 )")
	    );
		db.ExecuteUpdate(
			wxT("CREATE TABLE IF NOT EXISTS buddy_value (\
				 id INTEGER UNIQUE PRIMARY KEY,\
				 name TEXT,\
			     value NONE,\
				 buddyId INTEGER\
				 )")
	    );
		db.ExecuteUpdate(
			wxT("CREATE TABLE IF NOT EXISTS group_value (\
				 id INTEGER UNIQUE PRIMARY KEY,\
				 name TEXT,\
			     value NONE,\
				 groupId INTEGER\
				 )")
	    );
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createValueTables: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::createHistoryTable(){
	try{
		db.ExecuteUpdate(
			wxT("CREATE TABLE IF NOT EXISTS history (\
				 id INTEGER UNIQUE PRIMARY KEY,\
				 time INTEGER,\
				 buddyId INTEGER,\
				 message Text,\
				 out INTEGER,\
				 sessionId INTEGER,\
			     flags INTEGER\
				 )")
		 );

		db.ExecuteUpdate(
			wxT("CREATE TABLE IF NOT EXISTS history_session (\
				 id INTEGER UNIQUE PRIMARY KEY,\
				 buddyId INTEGER,\
				 timeStart INTEGER,\
				 timeEnd INTEGER\
			     )")
		 );
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createHistoryTable: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::createStatusMessageTable(){
	try{
		db.ExecuteUpdate(
			wxT("CREATE TABLE IF NOT EXISTS statusmsg (\
				 id INTEGER UNIQUE PRIMARY KEY,\
				 accountId INTEGER,\
				 status INTEGER,\
			     title TEXT,\
				 msg TEXT,\
				 flags INTEGER\
				 )")
	    );

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createStatusMessageTable: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::checkDatabaseTables(){
	checkAndCreate(wxT("history"), wxT("flags"), wxT("INTEGER"), wxT("0"));
	checkAndCreate(wxT("module"), wxT("type"), wxT("INTEGER"), wxT("0"));
	checkAndCreate(wxT("module"), wxT("flags"), wxT("INTEGER"), wxT("0"));
	checkAndCreate(wxT("module"), wxT("classname"), wxT("TEXT"), wxT("NULL"));
	checkAndCreate(wxT("buddy"), wxT("account_Id"), wxT("INTEGER"), wxT("1"));
	checkAndCreate(wxT("accounts"), wxT("self"), wxT("INTEGER"), wxT("0"));
	checkAndCreate(wxT("statusmsg"), wxT("accountId"), wxT("INTEGER"), wxT("1"));
}

bool Database::checkTableFiledExsists(const wxString & table, const wxString & field){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement(wxString::Format(wxT("SELECT 1 FROM %s WHERE %s=NULL LIMIT 1"), table.c_str(), field.c_str()));
	}catch(wxSQLite3Exception e){
		if(e.GetMessage().Contains(wxT("no such column:"))){
			return false;
		}
	}
	return true;
}
void Database::createTableField(const wxString & table, const wxString & field, const wxString & type, const wxString & defaultValue){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement(wxString::Format(wxT("ALTER TABLE %s ADD COLUMN %s %s DEFAULT %s"), table.c_str(), field.c_str(), type.c_str(), defaultValue.c_str()));
		stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createTableField: Exception: %s"), e.GetMessage().c_str());
	}
}

bool Database::checkAndCreate(const wxString & table, const wxString & field, const wxString & type, const wxString & defaultValue){
	if(!checkTableFiledExsists(table, field)){
		wxLogDebug(wxT("Database::checkAndCreate: Field %s of table %s didn't exsist, trying to create it"), field.c_str(), table.c_str());
		createTableField(table,field,type,defaultValue);
		return false;
	}
	return true;
}

DBModule Database::createModule(const wxString  & name){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("INSERT INTO module (name) VALUES (?)");
		stmt.Bind(1,name);
		stmt.ExecuteUpdate();
		return DBModule(this,db_id(db.GetLastRowId()));
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createModule: Exception: %s"), e.GetMessage().c_str());
	}
	return DBModule(this,db_id(0));
}

DBModule Database::getModule(const wxString  & name){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT id FROM module WHERE name=?");
		stmt.Bind(1,name);
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
		if(result.NextRow()){
			return DBModule(this,db_id(result.GetInt(0)));
		}
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::exsistsModule: Exception: %s"), e.GetMessage().c_str());
	}
	wxLogTrace(wxT("DATABASE"),wxT("Database::getModule: INFO: Module'%s' don't exsists -> creating!"), name.c_str() );
	return createModule(name);
}

void Database::close(){
	try{
		db.Close();
		wxLogTrace(wxT("DATABASE"),wxT("Database::disconnect: Datenbank geschlossen!"));
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::close: Exception: %s"), e.GetMessage().c_str());
	}
}

Buddy* Database::createBuddy(const db_id & accountId, const wxString & screenName, const wxString & custonName, Group* subGroup, const int & flags){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("INSERT INTO buddy (account_id, screen_name, custom_name, group_id, flags) VALUES(?,?,?,?,?)");
		stmt.Bind(1,accountId);
		stmt.Bind(2,screenName);
	    stmt.Bind(3,custonName);
	    stmt.Bind(4,subGroup->getId());
	    stmt.Bind(5,flags);

	    stmt.ExecuteUpdate();

	    Buddy* buddy = loadBuddyObject(db.GetLastRowId(), accountId, screenName, custonName, subGroup,flags);

	    if(flags & BUDDY_FLAG_SELF){
	    	selfs.push_back(dynamic_cast<SelfBuddy*>(buddy));
	    }else{
	    	buddies.push_back(buddy);
	    }

	    return buddy;
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createBuddy: Exception: %s"), e.GetMessage().c_str());
	}
	return NULL;
}

void Database::updateBuddyCustomName(Buddy* buddy, const wxString & customName){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("UPDATE buddy SET custom_name=? WHERE id=?");
	    stmt.Bind(1,customName);
	    stmt.Bind(2,buddy->getId());
	    stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::updateBuddyCustomName: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::updateBuddyScreenName(Buddy* buddy, const wxString & screenName){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("UPDATE buddy SET screen_name=? WHERE id=?");
	    stmt.Bind(1,screenName);
	    stmt.Bind(2,buddy->getId());
	    stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::updateBuddyScreenName: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::updateBuddyFlags(Buddy* buddy,const int & flags){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("UPDATE buddy SET flags=? WHERE id=?");
	    stmt.Bind(1,flags);
	    stmt.Bind(2,buddy->getId());
	    stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::updateBuddyFlags: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::updateGroup(Buddy* buddy, Group* newGroup){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("UPDATE buddy SET group_id=? WHERE id=?");
	    stmt.Bind(1,newGroup->getId());
	    stmt.Bind(2,buddy->getId());
	    stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::updateGroup: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::updateGroupFlags(Group* group,const int & flags){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("UPDATE gp SET flags=? WHERE id=?");
	    stmt.Bind(1,flags);
	    stmt.Bind(2,group->getId());
	    stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::updateGroupFlags: Exception: %s"), e.GetMessage().c_str());
	}
}


StatusAndMsg* Database::createStatusMessage(db_id accountId, const Status & status,const wxString & title, const wxString & msg, int flags){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("INSERT INTO statusmsg (accountId, status, title, msg, flags) VALUES(?,?,?,?,?)");
	    stmt.Bind(1, accountId);
		stmt.Bind(2, (int)status.getMask());
	    stmt.Bind(3, title);
	    stmt.Bind(4, msg);
	    stmt.Bind(5, flags);
	    stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createStatusMessage: Exception: %s"), e.GetMessage().c_str());
		return NULL;
	}

	StatusAndMsg* sam = new StatusAndMsg();
	sam->id=db.GetLastRowId();
	sam->title=title;
	sam->msg=msg;
	sam->status=status;
	sam->accountId=accountId;
	sam->flags=flags;

	return sam;
}

void Database::updateStatusMessage(StatusAndMsg* statusMsg){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("UPDATE statusmsg SET status=?, msg=?, title=?, flags=? WHERE id=?");
	    stmt.Bind(1,(int)statusMsg->status.getMask());
	    stmt.Bind(2,statusMsg->msg);
	    stmt.Bind(3,statusMsg->title);
	    stmt.Bind(4,statusMsg->flags);
	    stmt.Bind(5,statusMsg->id);
	    stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::updateStatusMessage: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::deleteStatusMessage(StatusAndMsg* statusMsg){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("DELETE FROM statusmsg WHERE id=?");
	    stmt.Bind(1,statusMsg->id);
	    stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::deleteDtatusMessage: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::getStatusMessages(std::vector<StatusAndMsg*>& out, db_id accountId){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT id,accountId, status,title,msg,flags FROM statusmsg WHERE accountId=?");
		stmt.Bind(1,accountId);
		wxSQLite3ResultSet result = stmt.ExecuteQuery();

		while (result.NextRow())
	    {
			StatusAndMsg* sam = new StatusAndMsg();
			sam->id = result.GetInt(0);
			sam->accountId=result.GetInt(1);
			sam->status = Status((Statusflag)result.GetInt(2));
			sam->title = result.GetString(3);
			sam->msg = result.GetString(4);
			sam->flags = result.GetInt(5);
			out.push_back(sam);
	    }

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getStatusMessages: Exception: %s"), e.GetMessage().c_str());
	}
}

Account* Database::createAccount(const int flags, const wxString & classname, const wxString & screenname, const wxString & password){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("INSERT INTO accounts (flags, classname, screenname, password, self) VALUES(?,?,?,?,0)");
	    stmt.Bind(1,flags);
	    stmt.Bind(2,classname);
	    stmt.Bind(3,screenname);
	    stmt.Bind(4,password);
	    stmt.ExecuteUpdate();

		db_id id = db.GetLastRowId();
		SelfBuddy* self = dynamic_cast<SelfBuddy*>(createBuddy(id, screenname, wxEmptyString, getRootGroup(), BUDDY_FLAG_SELF));
		wxASSERT(self != NULL);
		Account* account = new Account(id, flags, classname, screenname, password, self);

		updateAccount(account); //for self id;

		return account;
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createAccount: Exception: %s"), e.GetMessage().c_str());
		return NULL;
	}


}

void Database::getAccounts(std::vector<Account*> & accounts){

	wxSQLite3Statement stmt = db.PrepareStatement("SELECT id, flags, classname, screenname, password, self FROM accounts");
	wxSQLite3ResultSet result = stmt.ExecuteQuery();
    while(result.NextRow())
    {
    	db_id id = result.GetInt(0,-1);
    	int flags = result.GetInt(1,0);
    	wxString classname = result.GetString(2, wxEmptyString);
    	wxString screenname = result.GetString(3, wxEmptyString);
    	wxString password = result.GetString(4, wxEmptyString);
    	db_id selfId = result.GetInt(5,-1);
    	SelfBuddy* self = NULL;

    	std::vector<SelfBuddy*>::iterator is;
    	for(is = selfs.begin(); is != selfs.end(); is++){
    		SelfBuddy* s = *is;
    		if(s->getId() == selfId){
    			self = s;
    			break;
    		}
    	}

    	if(self == NULL){
    		wxLogError(wxT("Database::getAccounts: Coud not load Account, no self object forund"));
    	}else{
    		Account* account = new Account(id, flags, classname, screenname, password, self);
    		accounts.push_back(account);
    	}

    }

    /*
    if(accounts.size() == 0){
    	//create Master Account
    	Account* master = createAccount((int)ACCOUNT_FLAG_MASTER|(int)ACCOUNT_FLAG_ACTIVE, wxEmptyString, wxEmptyString, wxEmptyString);
    	accounts.push_back(master);
    }
    */
}

void Database::updateAccount(Account* account){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("UPDATE accounts SET flags=?, classname=?, screenname=?, password=?, self=? WHERE id=?");
	    stmt.Bind(1,account->flags);
	    stmt.Bind(2,account->classname);
	    stmt.Bind(3,account->screenname);
	    stmt.Bind(4,account->password);
	    stmt.Bind(5,account->self->getId());
	    stmt.Bind(6,account->id);
	    stmt.ExecuteUpdate();

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::updateAccount: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::deleteAccount(const db_id & id){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("DELETE FROM accounts WHERE id=?");
	    stmt.Bind(1,id);
	    stmt.ExecuteUpdate();

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::deleteAccount: Exception: %s"), e.GetMessage().c_str());
	}
}

db_id Database::saveInHistoryInSession(const wxDateTime & time, Buddy* buddy, const wxString & msg, bool out, const db_id & sessionId){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("INSERT INTO history (time,buddyId,message,out,sessionId) VALUES(?,?,?,?,?)");
	    stmt.BindNumericDateTime(1,time);
	    stmt.Bind(2,buddy->getId());
	    stmt.Bind(3,msg);
	    stmt.Bind(4,out);
	    stmt.Bind(5,sessionId);
	    stmt.ExecuteUpdate();

	    return db.GetLastRowId();

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::saveInHistoryInSession: Exception: %s"), e.GetMessage().c_str());
	}
	return 0;
}



db_id Database::saveInHistory(const wxDateTime & time, Buddy* buddy, const wxString & msg, bool out){
	try{
		HistorySession* session = getLastHistorySession(buddy);

		if(session==NULL){
			//buddy has never had a session so create the first
			session = createHistorySession(buddy,time);
		}else{
			//buddy has a session, so look if we can keep it or we have to  create a new one
			wxTimeSpan span = session->getTimeSinceLastMessage(time);

			if(span.GetHours() > 5){
				//session is too old, so create a new one
				//buddy deletes the old history session
				session = createHistorySession(buddy,time);
			}else{
				//we have just to update the last message time
				session->updateSessionEnd(time);
			}
		}

		wxASSERT(session != NULL);

		wxSQLite3Statement stmt = db.PrepareStatement("UPDATE history_session SET timeEnd=? WHERE id=?");
	    stmt.BindNumericDateTime(1,time);
	    stmt.Bind(2,session->getId());
	    stmt.ExecuteUpdate();

	    return  saveInHistoryInSession(time, buddy, msg, out, session->getId());

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::saveInHistory: Exception: %s"), e.GetMessage().c_str());
	}
	return 0;
}

/*
void Database::getHistoryEntriesBetween(std::vector<HistoryEntry*> & out, Buddy* buddy,const wxDateTime & after,const wxDateTime & before){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT time,senderId,receiverId,message FROM history WHERE senderId = ? OR receiverId = ? AND time BETWEEN ? AND ? ORDER BY time");
		stmt.Bind(1,buddy->getId());
		stmt.Bind(2,buddy->getId());
		stmt.BindNumericDateTime(3,after);
		stmt.BindNumericDateTime(4,before);

		wxSQLite3ResultSet result = stmt.ExecuteQuery();

		while (result.NextRow())
	    {
	    	wxDateTime time = result.GetNumericDateTime(0);
	    	db_id sid = result.GetInt64(1);
	    	db_id rid = result.GetInt64(2);
	    	wxString msg = result.GetString(3);

	    	Buddy* sender = getBuddy(sid);
	    	Buddy* receiver = getBuddy(rid);

	    	wxASSERT(sender != NULL);
	    	wxASSERT(receiver != NULL);

	    	HistoryEntry* temp = new HistoryEntry(time,sender,receiver,msg);
	    	out.push_back(temp);

	    	wxLogDebug(wxT("Message at: %s From: %i To: %i : %s"),time.FormatDate().c_str(),sid.ToLong(),rid.ToLong(),msg.c_str());

	    }
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getHistoryEntriesBetween: Exception: %s"), e.GetMessage().c_str());
	}
}
*/
Group* Database::createGroup(const wxString & name,const int & flags){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("INSERT INTO gp (name,flags) VALUES(?,?);");
		stmt.Bind(1,name);
	    stmt.Bind(2,flags);
	    stmt.ExecuteUpdate();
		Group* group = new Group(db.GetLastRowId(),name, flags);

		wxLogTrace(wxT("DATABASE"),wxT("Database::createGroup: Group %s, %i created"), name.c_str(), group->getId().ToLong());
		groups.push_back(group);

		return group;
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createGroup: Exception: %s"), e.GetMessage().c_str());
	}
	return NULL;
}

Group* Database::getGroup(db_id id){
	try{

		std::vector<Group*>::iterator dIter(groups.begin());
		for (; dIter != groups.end(); ++dIter) {
			if((*dIter)->getId() == id){
	    	  return (*dIter);
	      }
		}


		//it looks like group wasn't loaded...
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT name, flags FROM gp WHERE id=?");
	    stmt.Bind(1,id);
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    if(result.NextRow())
	    {
	    	return new Group(id,result.GetString(0),result.GetInt(1,0));
	    }
	    wxLogDebug(wxT("Database::getGroup: the group with id: %i wasn't found!"), id.ToLong());
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getGroup: Exception: %s"), e.GetMessage().c_str());
	}
	return NULL;
}

Buddy* Database::getBuddy(db_id id){
	try{
		std::vector<Buddy*>::iterator dIter(buddies.begin());
		for (; dIter != buddies.end(); ++dIter) {
			if((*dIter)->getId() == id){
	    	  return (*dIter);
	      }
		}

	    wxLogDebug(wxT("Database::getBuddy: the buddy with id: %i wasn't found!"), id.ToLong());
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getBuddy: Exception: %s"), e.GetMessage().c_str());
	}
	return NULL;
}

Group* Database::getRootGroup(){
	Group* rootGroup = getGroup(1);
	if(!rootGroup){
		wxLogTrace(wxT("DATABASE"),wxT("Database::getRootGroup: INFO: RootGroup not in db -> creating"));
		rootGroup = createGroup(wxT("root"), GROUP_ROOT);
		wxASSERT(rootGroup != NULL);
	}
	return rootGroup;
}

Group* Database::getNotInListGroup(std::vector<Group*> & g){
	if(notInListGroup == NULL){
		Group* nilG = createGroup(wxT("Not in List"),GROUP_NOT_IN_LIST);
		groups.push_back(nilG);
		g.push_back(nilG);
		return nilG;
		wxLogDebug(wxT("Database::getNotInListGroup: NotInList Group not present, creating!"));
	}else{
		return notInListGroup;
	}
}


void Database::getGroupsWithBuddies(std::vector<Group*> & groups, std::vector<Buddy*> & buddies){
	try{
		wxSQLite3ResultSet groupsResult = db.ExecuteQuery("SELECT id, name,flags FROM gp WHERE id!=1");

	    while (groupsResult.NextRow())
	    {
	    	int id = groupsResult.GetInt(0,-1);
	    	wxASSERT(id != -1);
	    	wxString name = groupsResult.GetString(1);
	    	int flags = groupsResult.GetInt(2,GROUP_NOFLAG);

	    	Group* curGroup = new Group(id,name,flags);
	    	groups.push_back(curGroup);

	    	if(curGroup->hasFlag(GROUP_NOT_IN_LIST)){
	    		notInListGroup=curGroup;
	    	}

	    }

	    this->groups = groups;

		wxSQLite3ResultSet buddyResult = db.ExecuteQuery("SELECT id,account_id,screen_name,custom_name,group_id,flags FROM buddy");

	    while (buddyResult.NextRow())
	    {
	    	int id = buddyResult.GetInt(0,-1);
	    	wxASSERT(id != -1);
	    	db_int accountId = buddyResult.GetInt(1,-1);
	    	wxASSERT(id != -1);
	    	wxString screenName = buddyResult.GetString(2);
	    	wxString customName = buddyResult.GetString(3);
	    	int groupId = buddyResult.GetInt(4,-1);
	    	int flags = buddyResult.GetInt(5,0);
	    	wxASSERT(groupId != -1);

			Group* subGroup = getGroup(groupId);
			if(!subGroup){
				wxLogDebug(wxT("DATABASE"),wxT("Database::getGroupsWithBuddies: SubGroup exsistiert nicht!!"));
				subGroup = getRootGroup();
			}

			Buddy* b = loadBuddyObject(id,accountId,screenName,customName,subGroup,flags);

			if(flags & BUDDY_FLAG_SELF){
				selfs.push_back(dynamic_cast<SelfBuddy*>(b));
			}else{
				buddies.push_back(b);
			}


	    }

	    this->buddies=buddies;

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getGroupsWithBuddies: Exception: %s"), e.GetMessage().c_str());
	}
}

//DBModule:

wxString Database::getStringValue(const db_id & moduleId,const  wxString & name,const wxString  & std){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM module_value WHERE name=? AND moduleId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,moduleId);
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    while(result.NextRow()){
	    	return result.GetString(0,std);
	    }
		return std;
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getStringValue: Exception: %s"), e.GetMessage().c_str());
	}
	return std;
}

db_int Database::getIntValue(const db_id & moduleId,const  wxString & name,const db_int & std){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM module_value WHERE name=? AND moduleId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,moduleId);
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    while(result.NextRow()){
	    	return result.GetInt(0,std);
	    }
		return std;
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getIntValue: Exception: %s"), e.GetMessage().c_str());
	}
	return std;
}

db_float Database::getFloatValue(const db_id & moduleId,const  wxString & name,const db_float & std){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM module_value WHERE name=? AND moduleId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,moduleId);
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    while(result.NextRow()){
	    	return result.GetDouble(0,std);
	    }
		return std;
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getFloatValue: Exception: %s"), e.GetMessage().c_str());
	}
	return std;
}

void Database::setStringValue(const db_id & moduleId,const wxString & name,const wxString  & value){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM module_value WHERE name=? AND moduleId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,moduleId);
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    bool exists = result.NextRow();
	    stmt.Reset();
		if(exists){
			stmt =  db.PrepareStatement("UPDATE module_value SET value=? WHERE name=? AND moduleId=?");
			stmt.Bind(1,value);
			stmt.Bind(2,name);
			stmt.Bind(3,moduleId);
		}else{
			stmt =  db.PrepareStatement("INSERT INTO module_value (name, value, moduleId) VALUES(?,?,?);");
			stmt.Bind(1,name);
			stmt.Bind(2,value);
			stmt.Bind(3,moduleId);
		}
		stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::setStringValue: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::setIntValue(const db_id & moduleId,const wxString & name,const db_int & value){
	try{


		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM module_value WHERE name=? AND moduleId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,moduleId);
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    bool exists = result.NextRow();
	    stmt.Reset();
		if(exists){
			stmt = db.PrepareStatement("UPDATE module_value SET value=? WHERE name LIKE ? AND moduleId = ?");
			stmt.Bind(1,value);
			stmt.Bind(2,name);
			stmt.Bind(3,moduleId);

		}else{
			stmt = db.PrepareStatement("INSERT INTO module_value (name, value, moduleId) VALUES(?,?,?);");
			stmt.Bind(1,name);
			stmt.Bind(2,value);
			stmt.Bind(3,moduleId);
		}
		stmt.ExecuteUpdate();


	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::setIntValue: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::setFloatValue(const db_id & moduleId,const wxString & name,const db_float & value){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM module_value WHERE name=? AND moduleId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,moduleId);
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    bool exists = result.NextRow();
	    stmt.Reset();
		if(exists){
			stmt =  db.PrepareStatement("UPDATE module_value SET value=? WHERE name=? AND moduleId=?");
			stmt.Bind(1,value);
			stmt.Bind(2,name);
			stmt.Bind(3,moduleId);
		}else{
			stmt =  db.PrepareStatement("INSERT INTO module_value (name, value, moduleId) VALUES(?,?,?);");
			stmt.Bind(1,name);
			stmt.Bind(2,value);
			stmt.Bind(3,moduleId);
		}
		stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::setFloatValue: Exception: %s"), e.GetMessage().c_str());
	}
}

//Buddy:

wxString Database::getStringValue(Buddy* buddy,const  wxString & name,const wxString  & std){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM buddy_value WHERE name=? AND buddyId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,buddy->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    while(result.NextRow()){
	    	return result.GetString(0,std);
	    }
		return std;
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getStringValue: Exception: %s"), e.GetMessage().c_str());
	}
	return std;
}

db_int Database::getIntValue(Buddy* buddy,const  wxString & name,const db_int & std){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM buddy_value WHERE name=? AND buddyId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,buddy->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    while(result.NextRow()){
	    	return result.GetInt(0,std);
	    }
		return std;
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getIntValue: Exception: %s"), e.GetMessage().c_str());
	}
	return std;
}

db_float Database::getFloatValue(Buddy* buddy,const  wxString & name,const db_float & std){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM buddy_value WHERE name=? AND buddyId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,buddy->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    while(result.NextRow()){
	    	return result.GetDouble(0,std);
	    }
		return std;
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getFloatValue: Exception: %s"), e.GetMessage().c_str());
	}
	return std;
}

void Database::setStringValue(Buddy* buddy,const wxString & name,const wxString  & value){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM buddy_value WHERE name=? AND buddyId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,buddy->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    bool exists = result.NextRow();
	    stmt.Reset();
		if(exists){
			stmt =  db.PrepareStatement("UPDATE buddy_value SET value=? WHERE name=? AND buddyId=?");
			stmt.Bind(1,value);
			stmt.Bind(2,name);
			stmt.Bind(3,buddy->getId());
		}else{
			stmt =  db.PrepareStatement("INSERT INTO buddy_value (name, value, buddyId) VALUES(?,?,?);");
			stmt.Bind(1,name);
			stmt.Bind(2,value);
			stmt.Bind(3,buddy->getId());
		}
		stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::setStringValue: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::setIntValue(Buddy* buddy,const wxString & name,const db_int & value){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM module_value WHERE name=? AND buddyId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,buddy->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    bool exists = result.NextRow();
	    stmt.Reset();
		if(exists){
			stmt =  db.PrepareStatement("UPDATE buddy_value SET value=? WHERE name=? AND buddyId=?");
			stmt.Bind(1,value);
			stmt.Bind(2,name);
			stmt.Bind(3,buddy->getId());
		}else{
			stmt =  db.PrepareStatement("INSERT INTO buddy_value (name, value, buddyId) VALUES(?,?,?);");
			stmt.Bind(1,name);
			stmt.Bind(2,value);
			stmt.Bind(3,buddy->getId());
		}
		stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::setIntValue: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::setFloatValue(Buddy* buddy,const wxString & name,const db_float & value){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM buddy_value WHERE name=? AND buddyId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,buddy->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    bool exists = result.NextRow();
	    stmt.Reset();
		if(exists){
			stmt =  db.PrepareStatement("UPDATE buddy_value SET value=? WHERE name=? AND buddyId=?");
			stmt.Bind(1,value);
			stmt.Bind(2,name);
			stmt.Bind(3,buddy->getId());
		}else{
			stmt =  db.PrepareStatement("INSERT INTO buddy_value (name, value, buddyId) VALUES(?,?,?);");
			stmt.Bind(1,name);
			stmt.Bind(2,value);
			stmt.Bind(3,buddy->getId());
		}
		stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::setFloatValue: Exception: %s"), e.GetMessage().c_str());
	}
}

//Group:


wxString Database::getStringValue(Group* group,const  wxString & name,const wxString  & std){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM group_value WHERE name=? AND groupId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,group->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    while(result.NextRow()){
	    	return result.GetString(0,std);
	    }
		return std;
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getStringValue: Exception: %s"), e.GetMessage().c_str());
	}
	return std;
}

db_int Database::getIntValue(Group* group,const  wxString & name,const db_int & std){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM group_value WHERE name=? AND groupId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,group->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    while(result.NextRow()){
	    	return result.GetInt(0,std);
	    }
		return std;
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getIntValue: Exception: %s"), e.GetMessage().c_str());
	}
	return std;
}

db_float Database::getFloatValue(Group* group,const  wxString & name,const db_float & std){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM group_value WHERE name=? AND groupId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,group->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    while(result.NextRow()){
	    	return result.GetDouble(0,std);
	    }
		return std;
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getFloatValue: Exception: %s"), e.GetMessage().c_str());
	}
	return std;
}

void Database::setStringValue(Group* group,const wxString & name,const wxString  & value){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM group_value WHERE name=? AND groupId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,group->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    bool exists = result.NextRow();
	    stmt.Reset();
		if(exists){
			stmt =  db.PrepareStatement("UPDATE group_value SET value=? WHERE name=? AND groupId=?");
			stmt.Bind(1,value);
			stmt.Bind(2,name);
			stmt.Bind(3,group->getId());
		}else{
			stmt =  db.PrepareStatement("INSERT INTO group_value (name, value, groupId) VALUES(?,?,?);");
			stmt.Bind(1,name);
			stmt.Bind(2,value);
			stmt.Bind(3,group->getId());
		}
		stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::setStringValue: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::setIntValue(Group* group,const wxString & name,const db_int & value){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM module_value WHERE name=? AND groupId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,group->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    bool exists = result.NextRow();
	    stmt.Reset();
		if(exists){
			stmt =  db.PrepareStatement("UPDATE group_value SET value=? WHERE name=? AND groupId=?");
			stmt.Bind(1,value);
			stmt.Bind(2,name);
			stmt.Bind(3,group->getId());
		}else{
			stmt =  db.PrepareStatement("INSERT INTO group_value (name, value, groupId) VALUES(?,?,?);");
			stmt.Bind(1,name);
			stmt.Bind(2,value);
			stmt.Bind(3,group->getId());
		}
		stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::setIntValue: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::setFloatValue(Group* group,const wxString & name,const db_float & value){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT value FROM group_value WHERE name=? AND groupId=?");
		stmt.Bind(1,name);
		stmt.Bind(2,group->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();
	    bool exists = result.NextRow();
	    stmt.Reset();
		if(exists){
			stmt =  db.PrepareStatement("UPDATE group_value SET value=? WHERE name=? AND groupId=?");
			stmt.Bind(1,value);
			stmt.Bind(2,name);
			stmt.Bind(3,group->getId());
		}else{
			stmt =  db.PrepareStatement("INSERT INTO group_value (name, value, groupId) VALUES(?,?,?);");
			stmt.Bind(1,name);
			stmt.Bind(2,value);
			stmt.Bind(3,group->getId());
		}
		stmt.ExecuteUpdate();
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::setFloatValue: Exception: %s"), e.GetMessage().c_str());
	}
}

HistorySession* Database::getLastHistorySession(Buddy* buddy){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT id, timeStart, timeEnd FROM history_session WHERE buddyId=? ORDER BY timeStart DESC LIMIT 1");
		stmt.Bind(1,buddy->getId());

		wxSQLite3ResultSet result = stmt.ExecuteQuery();

		while(result.NextRow()){
			db_id sessionId = result.GetInt64(0);
			wxASSERT(sessionId != 0);
			wxDateTime sessionStart = result.GetNumericDateTime(1);
			wxDateTime sessionEnd = result.GetNumericDateTime(2);
			return new HistorySession(sessionId,sessionStart,sessionEnd);
		}

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getLastHistorySession: Exception: %s"), e.GetMessage().c_str());
	}
	return NULL;
}

HistorySession* Database::createHistorySession(Buddy* buddy, const wxDateTime & sessionStart){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("INSERT INTO history_session (buddyId, timeStart, timeEnd) VALUES (?,?,?)");
		stmt.Bind(1,buddy->getId());
		stmt.BindNumericDateTime(2,sessionStart);
		stmt.BindNumericDateTime(3,sessionStart);
		stmt.ExecuteUpdate();

		return new HistorySession(db.GetLastRowId(),sessionStart,sessionStart);

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::createHistorySession: Exception: %s"), e.GetMessage().c_str());
	}
	return NULL;
}


HistorySession* Database::getCurrentHistorySession(Buddy* buddy){

	HistorySession* session = getLastHistorySession(buddy);

	if(session==NULL){
		//Buddy has not a cur session
		return NULL;
	}else{
		//buddy has a session, so look if is the current session
		wxTimeSpan span = session->getTimeSinceLastMessage(wxDateTime::Now());
		if(span.GetHours() > 5){
			//session is too old, so no cur session
			return NULL;
		}else{
			//we hava a cur session:
			return session;
		}
	}
}

void Database::getHistoryEntries(std::vector<HistoryEntry*> & out, HistorySession* session){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT id, time,buddyId,message,out FROM history WHERE sessionId=?");
		stmt.Bind(1,session->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();

		while (result.NextRow())
	    {
			db_id id = result.GetInt64(0);
	    	wxDateTime time = result.GetNumericDateTime(1);
	    	db_id buddyId = result.GetInt64(2);
	    	wxString msg = result.GetString(3);
	    	bool outgoing = result.GetBool(4);

	    	Buddy* buddy = getBuddy(buddyId);
	    	wxASSERT(buddy != NULL);

	    	HistoryEntry* temp = new HistoryEntry(id,time,buddy,msg,outgoing);

	    	out.push_back(temp);
	    }
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getHistoryEntries: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::getHistoryEntries(std::vector<HistoryEntry*> & out, Buddy* buddy,const wxDateTime & since){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT id, time, message, out FROM history WHERE time>=? AND buddyId==?");
		stmt.BindNumericDateTime(1, since);
		stmt.Bind(2, buddy->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();

		while (result.NextRow())
	    {
			db_id id = result.GetInt64(0);
	    	wxDateTime time = result.GetNumericDateTime(1);
	    	wxString msg = result.GetString(2);
	    	bool outgoing = result.GetBool(3);

	    	HistoryEntry* temp = new HistoryEntry(id,time,buddy,msg,outgoing);

	    	out.push_back(temp);
	    }
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getHistoryEntries: Exception: %s"), e.GetMessage().c_str());
	}
}

HistoryEntry* Database::getLastHistoryEntry(HistorySession* session){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT id,time,buddyId,message,out FROM history WHERE sessionId=? ORDER BY time DESC LIMIT 1");
		stmt.Bind(1,session->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();

		while (result.NextRow())
	    {
			db_id id = result.GetInt64(0);
	    	wxDateTime time = result.GetNumericDateTime(1);
	    	db_id buddyId = result.GetInt64(2);
	    	wxString msg = result.GetString(3);
	    	bool outgoing = result.GetBool(4);

	    	Buddy* buddy = getBuddy(buddyId);
	    	wxASSERT(buddy != NULL);

	    	return new HistoryEntry(id,time,buddy,msg,outgoing);
	    }
	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getLastEntry: Exception: %s"), e.GetMessage().c_str());
	}
	return NULL;
}

void Database::getHistoryYears(std::vector<int>& out, Buddy* buddy){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT DISTINCT strftime('%Y', timeStart/1000 , 'unixepoch', 'localtime')  FROM history_session WHERE buddyId=? ORDER BY timeStart");
		stmt.Bind(1,buddy->getId());
		wxSQLite3ResultSet result = stmt.ExecuteQuery();

		while (result.NextRow())
	    {
			int year = result.GetInt(0);
			out.push_back(year);
	    }

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getHistoryYears: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::getHistoryMonths(std::vector<int>& out, Buddy* buddy, int year){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT DISTINCT strftime('%m', timeStart/1000 , 'unixepoch', 'localtime')  FROM history_session WHERE buddyId=? AND strftime('%Y', timeStart/1000 , 'unixepoch', 'localtime') LIKE ? ORDER BY timeStart");
		stmt.Bind(1,buddy->getId());
		stmt.Bind(2,year);

		wxSQLite3ResultSet result = stmt.ExecuteQuery();

		while (result.NextRow())
	    {
			int month = result.GetInt(0);
			out.push_back(month);
	    }

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getHistoryMonths: Exception: %s"), e.GetMessage().c_str());
	}
}

void Database::getHistorySessions(std::vector<HistorySession*>& out, Buddy* buddy, int year, int month){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT id, timeStart, timeEnd FROM history_session WHERE buddyId=? AND strftime('%Y', timeStart/1000 , 'unixepoch', 'localtime') LIKE ? AND strftime('%m', timeStart/1000 , 'unixepoch', 'localtime') LIKE ? ORDER BY timeStart");
		stmt.Bind(1,buddy->getId());
		stmt.Bind(2,year);

		wxString tmp;

		if(month < 10){
			tmp << wxT("0");
		}
		tmp << month;

		stmt.Bind(3,tmp);

		wxSQLite3ResultSet result = stmt.ExecuteQuery();

		while (result.NextRow())
	    {
			db_id sessionId = result.GetInt64(0);
			wxASSERT(sessionId != 0);
			wxDateTime sessionStart = result.GetNumericDateTime(1);
			wxDateTime sessionEnd = result.GetNumericDateTime(2);

			HistorySession* session = new HistorySession(sessionId,sessionStart,sessionEnd);
			out.push_back(session);
	    }

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::getHistorySessions: Exception: %s"), e.GetMessage().c_str());
	}
}

bool Database::doesHistoryEntryExist(Buddy* buddy, bool out, wxDateTime time, const wxString& msg){
	try{
		wxSQLite3Statement stmt = db.PrepareStatement("SELECT id FROM history WHERE buddyId=? AND time=? AND out=? AND message=? LIMIT 1");
		stmt.Bind(1,buddy->getId());
		stmt.BindNumericDateTime(2, time);
		stmt.Bind(3, out);
		stmt.Bind(4, msg);

		wxSQLite3ResultSet result = stmt.ExecuteQuery();

		while (result.NextRow())
	    {
			return true;
	    }

	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::doesHistoryEntryExist: Exception: %s"), e.GetMessage().c_str());
		return false;
	}
	return false;
}


void Database::recreateHistorySessions(Buddy* buddy){
	try{

		wxSQLite3Statement stmt = db.PrepareStatement("DELETE FROM history_session WHERE buddyId=?");
		stmt.Bind(1,buddy->getId());
		stmt.ExecuteUpdate();
		stmt.Reset();

		//wxLogDebug(wxT("all entries deleted"));


		wxSQLite3Statement stmt2 = db.PrepareStatement("SELECT id, time FROM history WHERE buddyId=? ORDER BY time");
		stmt2.Bind(1,buddy->getId());
		wxSQLite3ResultSet result = stmt2.ExecuteQuery();

		//wxLogDebug(wxT("getting all"));

		wxDateTime lastTime;
		wxDateTime lastSessionStart;

		size_t count = 0;
		std::vector<db_id> lastSessionIds;

		while (result.NextRow())
	    {
			lastSessionIds.push_back(result.GetInt64(0));
			//wxLogDebug(wxT("blub %s"), result.GetInt64(0).ToString().c_str());

			if(count == 0){
				lastTime = result.GetNumericDateTime(1);
				lastSessionStart = lastTime;
				count++;
				continue;
			}
			wxDateTime curTime = result.GetNumericDateTime(1);;

			//wxLogDebug(wxT("cur time: %s lastTime: %s"), curTime.FormatTime().c_str(), lastTime.FormatTime().c_str());

			wxTimeSpan span = curTime.Subtract(lastTime);

			if(span.GetHours() > 5){
				//wxLogDebug(wxT("new session %i"), span.GetDays());
				stmt.Reset();
				stmt = db.PrepareStatement("INSERT INTO history_session(buddyId, timeStart, timeEnd) VALUES(?,?,?)");
				stmt.Bind(1, buddy->getId());
				stmt.BindNumericDateTime(2, lastSessionStart);
				stmt.BindNumericDateTime(3, lastTime);
				stmt.ExecuteUpdate();

				db_id last = db.GetLastRowId();

				for(size_t i=0; i < lastSessionIds.size()-1; i++){
					stmt.Reset();
					db_id id = lastSessionIds[i];
					stmt = db.PrepareStatement("UPDATE history SET sessionId=? WHERE id=?");
					stmt.Bind(1, last);
					stmt.Bind(2, id);
					stmt.ExecuteUpdate();
				}
				lastSessionIds.clear();
				lastSessionIds.push_back(result.GetInt64(0));
				lastSessionStart = curTime;
			}

			lastTime = curTime;
			count++;
	    }

		if(count != 0){
			stmt.Reset();
			stmt = db.PrepareStatement("INSERT INTO history_session(buddyId, timeStart, timeEnd) VALUES(?,?,?)");
			stmt.Bind(1, buddy->getId());
			stmt.BindNumericDateTime(2, lastSessionStart);
			stmt.BindNumericDateTime(3, lastTime);
			stmt.ExecuteUpdate();

			db_id last = db.GetLastRowId();

			for(size_t i=0; i < lastSessionIds.size(); i++){
				stmt.Reset();
				db_id id = lastSessionIds[i];
				stmt = db.PrepareStatement("UPDATE history SET sessionId=? WHERE id=?");
				stmt.Bind(1, last);
				stmt.Bind(2, id);
				stmt.ExecuteUpdate();
			}
			lastSessionIds.clear();
		}


	}catch(wxSQLite3Exception e){
		wxLogDebug(wxT("Database::recreateHistorySessions: Exception: %s"), e.GetMessage().c_str());
	}
}

Buddy* Database::loadBuddyObject(const db_id & id, const db_id & accountId,const wxString & screenName, const wxString & customName, Group* subGroup, const int & flags){

	Buddy* b = NULL;

	if(flags & BUDDY_FLAG_SELF){
		b = new SelfBuddy(id,accountId,screenName,customName,subGroup,flags);
	}else{
		b = new Buddy(id,accountId,screenName,customName,subGroup,flags);
	}

	b->setProtocolData(new OscarProtData());

	wxString avatar = getStringValue(b,wxT("avatar"),wxEmptyString);
	if(!avatar.IsEmpty()){


		//migration: for old database files
		if(avatar.Contains(wxT("avatar"))){
			avatar.Replace(wxT("avatar/"),wxT(""),false);
			setStringValue(b,wxT("avatar"),avatar);
		}

		avatar = wxString::Format(wxT("%s/%s"), Impp::exemplar()->getAvatarDir().c_str(), avatar.c_str());

		bool succes = b->setAvatar(avatar);
		if(!succes){
			setStringValue(b,wxT("avatar"),wxEmptyString);
		}
	}

	return b;
}


}
